
import 'package:k3cloud_api/http/k3client.dart';
import 'package:k3cloud_api/params/iface_model.dart';
import 'package:k3cloud_api/params/imp/audit.dart';
import 'package:k3cloud_api/params/imp/delete.dart';
import 'package:k3cloud_api/params/imp/login.dart';
import 'package:k3cloud_api/params/imp/metaquery.dart';
import 'package:k3cloud_api/params/imp/push.dart';
import 'package:k3cloud_api/params/imp/query.dart';
import 'package:k3cloud_api/params/imp/save.dart';
import 'package:k3cloud_api/params/imp/submit.dart';
import 'package:k3cloud_api/params/imp/switch_org.dart';
import 'package:k3cloud_api/params/imp/unaudit.dart';
import 'package:k3cloud_api/params/imp/view.dart';
import 'package:k3cloud_api/params/imp/workflow_audit.dart';
import 'package:k3cloud_api/params/model/response_status.dart';
import 'package:k3cloud_api/params/model/login_info.dart';
import 'package:k3cloud_api/params/model/user_context.dart';
import 'package:k3cloud_api/params/request_param.dart';

/// For approval.
enum ApprovalType {
  /// Audit pass
  pass,
  /// Reject the bill
  reject,
  /// Terminate the workflow
  termination
}

/// Some high-level api for simple requesting.
class KdApi {

  /// Check if the user has logined.
  static bool isLogin() => K3Client.getInstance().loginInfo?.isLoginSuccess ?? false;

  /// Get the logined user information.
  static UserContext? getCurrentUser() => K3Client.getInstance().loginInfo?.context;

  /// Use to login to get the user information.
  /// 
  /// [domain] The IP or server's domain
  /// [acctID] The datacenter's ID.
  /// [username] The username to login
  /// [password] The password of the user
  /// 
  /// @return The user's information
  static Future<LoginInfo> login(String domain, String acctID, String username, String password) async {
    var p = LoginParam.builder()
      .acctID(acctID)
      .username(username)
      .password(password)
      .build();
    return K3Client.getInstance()
      .setDomain(domain)
      .login(p);
  }

  /// This method is used to query data from Kingdee Cloud's forms.
  /// 
  /// [formId] The formId of the bill or basedata.
  /// [fieldKeys] The field key's names.
  /// [filterString] The filter srting, likely SQL's where.
  /// [orderString] The order srting, likely SQL's order by.
  /// [pageIdex] The page's index.
  /// [pageSize] The page's size.
  /// 
  /// @return Json data.
  static Future<Map<String, dynamic>> query({
    required String formId, 
    required List<String> fieldKeys,
    String filterString="",
    String orderString="",
    int pageIdex=1,
    int pageSize=20,
  }) {
    return K3Client.getInstance().operate(
      QueryParam.builder()
        .formId(formId)
        .fieldKeys(fieldKeys)
        .filterString(filterString)
        .orderString(orderString)
        .startRow((pageIdex-1)*pageSize)
        .limit(pageSize)
        .build()
    );
  }

  /// Base request method.
  ///
  /// [param] request parameter
  ///
  /// @return Json data.
  static Future<Map<String, dynamic>> operate(RequestParam param) {
    return K3Client.getInstance().operate(param);
  }


  /// This method is used to view all fields of one bill form or one basedata.
  /// 
  /// [formId] The formId of the bill or basedata.
  /// [number] The bill's BillNo or the basedata's Number
  /// 
  /// @return Json data.
  static Future<Map<String, dynamic>> view(String formId, String number) {
    return K3Client.getInstance().operate(
      ViewParam.builder()
        .formId(formId)
        .number(number)
        .build()
    );
  }

  /// One bill or many bills to one bill push.
  /// 
  /// [numbers] The billnos of source bills.
  /// [formId] The formId of the source bill.
  /// [targetFormId] The formId of the target bill.
  /// 
  /// @return Json data.
  static Future<ResponseStatus> push(List<String> numbers, String formId, String targetFormId) async {
    var resp = await K3Client.getInstance().operate(
      PushParam.builder()
        .isEnableDefaultRule(true)
        .formId(formId)
        .numbers(numbers)
        .targetFormId(targetFormId)
        .build()
    );
    return ResponseStatus.fromJson(resp);
  }

  /// One bill or many bills to one bill push.
  /// 
  /// [ids] The ids of source bills.
  /// [formId] The formId of the source bill.
  /// [targetFormId] The formId of the target bill.
  /// 
  /// @return Json data.
  static Future<ResponseStatus> pushById(List<int> ids, String formId, String targetFormId) async {
    var resp = await K3Client.getInstance().operate(
      PushParam.builder()
        .isEnableDefaultRule(true)
        .formId(formId)
        .ids(ids)
        .targetFormId(targetFormId)
        .build()
    );
    return ResponseStatus.fromJson(resp);
  }

  /// One bill or many bills to one bill push.
  /// 
  /// [entryIds] The ids of source bills.
  /// [formId] The formId of the source bill.
  /// [targetFormId] The formId of the target bill.
  /// 
  /// @return Json data.
  static Future<ResponseStatus> pushByEntryId(List<int> entryIds, String formId, String targetFormId) async {
    var resp = await K3Client.getInstance().operate(
      PushParam.builder()
        .isEnableDefaultRule(true)
        .formId(formId)
        .entryIds(entryIds)
        .targetFormId(targetFormId)
        .build()
    );
    return ResponseStatus.fromJson(resp);
  }

  static Future<ResponseStatus> pushByParam(PushParam param) async {
    var resp = await K3Client.getInstance().operate(param);
    return ResponseStatus.fromJson(resp);
  }

  /// Directly save json data.
  /// 
  /// [formId] The formId of the bill or basedata.
  /// [json] Json data.
  /// [isDeleteEntry] Before saving, it is wheter delete the entry.
  /// [isAutoSubmitAndAudit] Whehter to automatic audit.
  /// 
  /// @return A response model.
  static Future<ResponseStatus> saveJson(
    String formId, Map<String, dynamic> json, 
    {
      bool isDeleteEntry=true, 
      bool isAutoSubmitAndAudit=false,
      List<String>? needUpDateFields,
      List<String>? needReturnFields,
    }) async {
    var resp = await K3Client.getInstance().operate(
      SaveParam.builder()
        .formId(formId)
        .isDeleteEntry(isDeleteEntry)
        .isAutoSubmitAndAudit(isAutoSubmitAndAudit)
        .needUpDateFields(needUpDateFields)
        .needReturnFields(needReturnFields)
        .model(json)
        .build()
    );
    return ResponseStatus.fromJson(resp);
  }

  /// Directly save json data.
  /// 
  /// [T] The type of a model, which should implement [IModel] to implement the toJson method.
  /// [formId] The formId of the bill or basedata.
  /// [model] Data.
  /// [isDeleteEntry] Before saving, it is wheter delete the entry.
  /// [isAutoSubmitAndAudit] Whehter to automatic audit.
  /// 
  /// @return A response result by parsing json.
  static Future<ResponseStatus> save<T extends IModel>(
    String formId, T model, 
    {
      bool isDeleteEntry=true, 
      bool isAutoSubmitAndAudit=false,
      List<String>? needUpDateFields,
      List<String>? needReturnFields,
    }) async {
    var resp = await K3Client.getInstance().operate(
      SaveParam.builder()
        .formId(formId)
        .isDeleteEntry(isDeleteEntry)
        .isAutoSubmitAndAudit(isAutoSubmitAndAudit)
        .needUpDateFields(needUpDateFields)
        .needReturnFields(needReturnFields)
        .model(model.toJson())
        .build()
    );
    return ResponseStatus.fromJson(resp);
  }

  /// Submit some bills by billNos, and it can trigger the approval flow.
  /// 
  /// [formId] The formId of the bill or basedata.
  /// [billNos] The billnos of bills or the numbers of basedatas.
  /// 
  /// @return A response result by parsing json.
  static Future<ResponseStatus> submit(String formId, List<String> numbers) async {
    var resp = await K3Client.getInstance().operate(
      SubmitParam.builder()
        .formId(formId)
        .numbers(numbers)
        .build()
    );
    return ResponseStatus.fromJson(resp);
  }

  /// Audit some bills by billNos.
  /// 
  /// [formId] The formId of the bill or basedata.
  /// [numbers] The billnos of bills or the numbers of basedatas.
  /// 
  /// @return A response result by parsing json.
  static Future<ResponseStatus> audit(String formId, List<String> numbers) async {
    var resp = await K3Client.getInstance().operate(
      AuditParam.builder()
        .formId(formId)
        .numbers(numbers)
        .build()
    );
    return ResponseStatus.fromJson(resp);
  }

  static Future<ResponseStatus> auditById(String formId, List<int> ids) async {
    var resp = await K3Client.getInstance().operate(
      AuditParam.builder()
        .formId(formId)
        .ids(ids)
        .build()
    );
    return ResponseStatus.fromJson(resp);
  }

  /// UnAudit some bills by billNos.
  /// 
  /// [formId] The formId of the bill or basedata.
  /// [numbers] The billnos of bills or the numbers of basedatas.
  /// 
  /// @return A response result by parsing json.
  static Future<ResponseStatus> unAudit(String formId, List<String> numbers) async {
    var resp = await K3Client.getInstance().operate(
      UnAuditParam.builder()
        .formId(formId)
        .numbers(numbers)
        .build()
    );
    return ResponseStatus.fromJson(resp);
  }

  static Future<ResponseStatus> unAuditById(String formId, List<int> ids) async {
    var resp = await K3Client.getInstance().operate(
      UnAuditParam.builder()
        .formId(formId)
        .ids(ids)
        .build()
    );
    return ResponseStatus.fromJson(resp);
  }

  /// Delete some bills by billNos.
  /// 
  /// [formId] The formId of the bill or basedata.
  /// [numbers] The billnos of bills or the numbers of basedatas.
  /// 
  /// @return A response result by parsing json.
  static Future<ResponseStatus> delete(String formId, List<String> numbers) async {
    var resp = await K3Client.getInstance().operate(
      DeleteParam.builder()
        .formId(formId)
        .numbers(numbers)
        .build()
    );
    return ResponseStatus.fromJson(resp);
  }

  static Future<ResponseStatus> deleteById(String formId, List<int> ids) async {
    var resp = await K3Client.getInstance().operate(
      DeleteParam.builder()
        .formId(formId)
        .ids(ids)
        .build()
    );
    return ResponseStatus.fromJson(resp);
  }

  /// Simple workfow audit.
  /// 
  /// [formId] The formId of the bill or basedata.
  /// [numbers] The billnos of bills or the numbers of basedatas.
  /// [userId] The auditor's user ID of current workflow node.
  /// [approvalType] The approval type
  /// 
  /// @return A response result by parsing json.
  static Future<ResponseStatus> simpleWorkflowAudit(String formId, List<String> numbers, int userId, ApprovalType approval) async {
    var resp = await K3Client.getInstance().operate(
      WorkflowAuditParam.builder()
        .formId(formId)
        .numbers(numbers)
        .userId(userId)
        .approvalType(approval.index+1)
        .build()
    );
    return ResponseStatus.fromJson(resp);
  }

  static Future<ResponseStatus> simpleWorkflowAuditById(String formId, List<int> ids, int userId, ApprovalType approval) async {
    var resp = await K3Client.getInstance().operate(
      WorkflowAuditParam.builder()
        .formId(formId)
        .ids(ids)
        .userId(userId)
        .approvalType(approval.index+1)
        .build()
    );
    return ResponseStatus.fromJson(resp);
  }

  /// The workfow audit which customs the options of audited action.
  /// 
  /// [formId] The formId of the bill or basedata.
  /// [numbers] The billnos of bills or the numbers of basedatas.
  /// [userId] The auditor's user ID of current workflow node.
  /// [action] The number of the audited item in the workfow node.
  /// 
  /// @return A response result by parsing json.
  static Future<ResponseStatus> workflowAudit(String formId, List<String> numbers, int userId, String action) async {
    var resp = await K3Client.getInstance().operate(
      WorkflowAuditParam.builder()
        .formId(formId)
        .numbers(numbers)
        .userId(userId)
        .actionResultId(action)
        .build()
    );
    return ResponseStatus.fromJson(resp);
  }

  static Future<ResponseStatus> workflowAuditById(String formId, List<int> ids, int userId, String action) async {
    var resp = await K3Client.getInstance().operate(
      WorkflowAuditParam.builder()
        .formId(formId)
        .ids(ids)
        .userId(userId)
        .actionResultId(action)
        .build()
    );
    return ResponseStatus.fromJson(resp);
  }

  /// The bill's meta data' query.
  /// 
  /// [formId] The formId of the bill or basedata.
  /// 
  /// @return Json data.
  static Future<Map<String, dynamic>> metaQuery(String formId) {
    return K3Client.getInstance().operate(
      MetaQueryParam(formId: formId)
    );
  }

  /// Switch the current user's orgnization.
  /// 
  /// [orgNumber] The number of the orgnization.
  /// 
  /// @return Json data.
  static Future<Map<String, dynamic>> switchOrg(String orgNumber) {
    return K3Client.getInstance().operate(
      SwitchOrgParam(orgNumber: orgNumber)
    );
  }
}